/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#pragma once

#if defined(DEBUG) || defined(_DEBUG)
#define BAJA_DEBUG
#endif

#if defined(WIN32) || defined(_WIN32)
#define BAJA_WIN32
#endif

#ifdef BAJA_WIN32
#if (defined (_MSC_VER) && _MSC_VER > 1300)
#define BAJA_INLINE __forceinline
#else
#define BAJA_INLINE inline
#endif
#endif

#if (defined (WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_APP)
#define BAJA_WINRT
#endif

// stl
#include <string>
#include <sstream>
#include <functional>
#include <algorithm>
#include <exception>
#include <map>
#include <vector>
#include <memory>
#include <mutex>
#include <set>

// boost
#include <boost/format.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/string_generator.hpp>

// types
#include <baja/types.hpp>

#define BAJA_DECLARE_TAG(tag_) \
static const ::baja::tag& getTag() \
{ \
    static ::baja::tag t = boost::uuids::string_generator()(std::string(tag_)); \
    return t; \
}

#define BAJA_INTERFACE(i_, tag_) \
public: \
    i_() {} \
    virtual ~i_() {} \
    BAJA_DECLARE_TAG(tag_)

#define BAJA_INTERFACE_NOTAG(i_) \
public: \
    i_() {} \
    virtual ~i_() {}

namespace baja
{

template <class Ti> const baja::tag& getTag()
{
    return Ti::getTag();
}

struct ibase
{
    BAJA_INTERFACE(ibase,"B2238BC0-12F4-4975-9E86-C2921E24E84E")
};

} // namespace baja

#define BAJA_INTERFACE_END };

// flags
// DEADCODE:
#if 0
#define BAJA_BEGIN_DECLARE_FLAGS_WITH_TYPE(f, t) \
enum class f : t; \
f BAJA_INLINE operator|(const f& l, const f& r) { return static_cast<f>(static_cast<t>(l) | static_cast<t>(r)); } \
f BAJA_INLINE operator|=(f& l, const f& r) { return (l = l | r); } \
f BAJA_INLINE operator&=(f& l, const f& r) { return l = static_cast<f>(static_cast<t>(l) & static_cast<t>(r)); } \
f BAJA_INLINE operator&(const f& l, const f& r) { return static_cast<f>(static_cast<t>(l) & static_cast<t>(r)); } \
f BAJA_INLINE operator~(const f& l) { return static_cast<f>(~static_cast<t>(l)); } \
enum class f : t { 

#define BAJA_END_DECLARE_FLAGS };

#define BAJA_BEGIN_DECLARE_FLAGS(f) BAJA_BEGIN_DECLARE_FLAGS_WITH_TYPE(f, unsigned int)
#endif

#define MAKE_WIDE_(s) L#s
#define MAKE_WIDE(s) MAKE_WIDE_(s)

// global definition helpers
#define BAJA_BEGIN_GLOBALS(c_) template <class T> struct c_##_t {
#define BAJA_DECLARE_GLOBAL(t_, n_) static t_ n_;
#define BAJA_DECLARE_CONST_GLOBAL(t_, n_) static const t_ n_;
#define BAJA_END_GLOBALS(c_) }; typedef c_##_t<int> c_;

#define BAJA_DEFINE_GLOBAL(c_, t_, n_, v_) template <class T> t_ c_##_t<T>::n_ = v_;
#define BAJA_DEFINE_CONST_GLOBAL(c_, t_, n_, v_) template <class T> const t_ c_##_t<T>::n_ = v_;

#define BAJA_BEGIN_CONSTANTS(c_) namespace c_ {
#define BAJA_DECLARE_CONST(t_, n_, v_) const t_ n_ = v_;
#define BAJA_END_CONSTANTS };

// dynamic cast for weak pointers
// DEADCODE:
#if 0
namespace baja {
template <class Tdst, class Tsrc>
std::weak_ptr<Tdst> dynamic_pointer_cast(
    const std::weak_ptr<Tsrc>& src
    )
{
    std::shared_ptr<Tsrc> s_src(src.lock());
    std::shared_ptr<Tdst> s_dst = std::dynamic_pointer_cast<Tdst, Tsrc>(s_src);
    return s_dst;
}
} // namespace baja
#endif

#define BAJA_LOCK(m) std::lock_guard<std::recursive_mutex> __lock(m)
#define BAJA_LOCK_N(n,m) std::lock_guard<std::recursive_mutex> __lock##n(m)
